home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000 #2
/
Ham Radio 2000 - Volume 2.iso
/
HAMV2
/
TCP_IP
/
TNOS230S
/
N8250.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-24
|
22KB
|
963 lines
/* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC
* Copyright 1991 Phil Karn, KA9Q
*
* 16550A support plus some statistics added mah@hpuviea.at 15/7/89
*
* CTS hardware flow control from dkstevens@ucdavis,
* additional stats from delaroca@oac.ucla.edu added by karn 4/17/90
* Feb '91 RLSD line control reorganized by Bill_Simpson@um.cc.umich.edu
* Sep '91 All control signals reorganized by Bill Simpson
* Apr '92 Control signals redone again by Phil Karn
*/
#ifdef MSDOS
#include "global.h"
#include <dos.h>
#include "mbuf.h"
#include "proc.h"
#include "iface.h"
#include "n8250.h"
#include "asy.h"
#include "devparam.h"
#include "hardware.h"
#include "kisspoll.h"
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: n8250.c,v 1.6 1997/05/24 22:13:02 root Exp root $";
#endif
#if 0 /* was def TIPMAIL */
#include "cmdparse.h"
extern struct cmds Cmds[];
#endif
static int get_rlsd_asy (int dev, int new_rlsd);
static void asyrxint (struct asy *asyp, unsigned base);
static void asytxint (struct asy *asyp, unsigned base);
static void asymsint (struct asy *asyp);
static void asycom (struct asy *);
static void asy_monitor (int dev, void *p1, void *p2);
void pasy (struct asy *asyp);
struct asy *Asy; /* allocated in main.c */
static unsigned char fifo_setup;
#ifdef DEBUGASY
static unsigned long ierints = 0;
#endif
static void asyint (int dev);
extern int arddec (volatile int *p);
/* Initialize asynch port "dev" */
int
asy_init (
int dev,
struct iface *ifp,
char *arg1,
char *arg2,
int16 bufsize,
int trigchar,
char monitor,
long speed,
int force,
int triglevel,
int polled
)
{
struct fifo *fp;
struct asy *ap;
int chain = 0;
char *ifn;
long interval;
unsigned int base;
ap = &Asy[dev];
ap->iface = ifp;
ap->addr = htoi (arg1);
ap->vec = htoi (arg2);
#ifdef POLLEDKISS
ap->poller = NULL;
#endif
ap->chain = chain;
/* Set up receiver FIFO */
fp = &ap->fifo;
fp->buf = mallocw (bufsize);
fp->bufsize = bufsize;
fp->wp = fp->rp = fp->buf;
fp->cnt = 0;
fp->hiwat = 0;
fp->overrun = 0;
base = ap->addr;
ap->trigchar = trigchar;
/* Purge the receive data buffer */
(void) inportb (base + RBR);
/* Save original mask state, force off interrupts for now */
if (ap->vec != -1) {
ap->save.mask = getmask (ap->vec);
(void) maskoff (ap->vec);
}
ap->save.lcr = inportb (base + LCR);
ap->save.ier = inportb (base + IER);
ap->save.mcr = inportb (base + MCR);
ap->msr = ap->save.msr = inportb (base + MSR);
ap->save.iir = inportb (base + IIR);
/* save speed bytes */
setbit (base + LCR, LCR_DLAB);
ap->save.divl = inportb (base + DLL);
ap->save.divh = inportb (base + DLM);
clrbit (base + LCR, LCR_DLAB);
/* save some information on the starting state */
ap->cts_flow_control = (ap->save.msr & MSR_CTS) ? FOUND_UP : FOUND_DOWN;
ap->rlsd_line_control = (ap->save.msr & MSR_RLSD) ? FOUND_UP : FOUND_DOWN;
ap->dtr_usage = (ap->save.mcr & MCR_DTR) ? FOUND_UP : FOUND_DOWN;
ap->rts_usage = (ap->save.mcr & MCR_RTS) ? FOUND_UP : FOUND_DOWN;
/* Set interrupt vector to SIO handler */
if (ap->vec != -1) {
LOCK_FUNCTION(asyint);
LOCK_VARIABLE(Asy);
(void) setvect (ap->vec, chain, asyint, dev);
}
/* Set line control register: 8 bits, no parity */
outportb (base + LCR, LCR_8BITS);
/* Set the fifo trigger level according to the user's wishes :-) - WG7J */
if (triglevel == 1)
fifo_setup = FIFO_SETUP1;
else if (triglevel == 4)
fifo_setup = FIFO_SETUP4;
else if (triglevel == 8)
fifo_setup = FIFO_SETUP8;
else if (triglevel == 14)
fifo_setup = FIFO_SETUP14;
else
fifo_setup = FIFO_SETUP4; /* default to 4 */
/* determine if 16550A, turn on FIFO mode and clear RX and TX FIFOs */
outportb (base + FCR, FIFO_ENABLE);
/* According to National ap note AN-493, the FIFO in the 16550 chip
* is broken and must not be used. To determine if this is a 16550A
* (which has a good FIFO implementation) check that both bits 7
* and 6 of the IIR are 1 after setting the fifo enable bit. If
* not, don't try to use the FIFO.
*/
if ((inportb (base + IIR) & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED || force) {
ap->is_16550a = TRUE;
outportb (base + FCR, fifo_setup);
} else {
/* Chip is not a 16550A. In case it's a 16550 (which has a
* broken FIFO), turn off the FIFO bit.
*/
outportb (base + FCR, 0);
ap->is_16550a = FALSE;
}
/* Turn on receive interrupts and modem interrupts;
* leave transmit interrupts off until we actually send data.
*/
outportb (base + IER, IER_RLS | IER_DAV | IER_MS);
/* Turn on 8250 master interrupt enable (connected to OUT2) */
setbit (base + MCR, MCR_OUT2);
/* Enable interrupt */
if (ap->vec != -1)
(void) maskon (ap->vec);
(void) asy_speed (dev, speed);
if (monitor) {
/* set up to monitor line signals */
ap->monitor = newproc (ifn = if_name (ifp, " monitor"),
256, asy_monitor, ifp->dev, ifp, NULL, 0);
free (ifn);
kwait (NULL); /* let hooks get set up */
}
if ((ap->dtr_usage & FOUND_UP) && (ap->rlsd_line_control & FOUND_UP) || ap->monitor == NULL) {
if (ifp->iostatus != NULL)
(void) (*ifp->iostatus) (ifp, PARAM_UP, 0L);
}
#ifdef POLLEDKISS
if (polled) {
/* Calculate the poll interval: some processing time +
* the packet duration for a mtu size packet.
*/
interval = (((long) ifp->mtu * 10000L) / speed);
ap->poller = newproc (ifn = if_name (ifp, " poller"),
384, kiss_poller, ifp->xdev, (void *) interval, NULL, 0);
free (ifn);
}
#endif
return 0;
}
int
asy_stop (struct iface *ifp)
{
unsigned base;
struct asy *ap;
ap = &Asy[ifp->dev];
#ifdef POLLEDKISS
if (ap->poller)
killproc (ap->poller);
#endif
if (ap->monitor != NULL) {
ap->rlsd_line_control = IGNORED;
killproc (ap->monitor);
ap->monitor = NULL;
}
if (ap->iface == NULL)
return -1; /* Not allocated */
ap->iface = NULL;
base = ap->addr;
(void) inportb (base + RBR); /* Purge the receive data buffer */
if (ap->is_16550a) {
/* Purge hardware FIFOs and disable if we weren't already
* in FIFO mode when we entered. Apparently some
* other comm programs can't handle 16550s in
* FIFO mode; they expect 16450 compatibility mode.
*/
outportb (base + FCR, fifo_setup);
if ((ap->save.iir & IIR_FIFO_ENABLED) != IIR_FIFO_ENABLED)
outportb (base + FCR, 0);
}
/* Restore original interrupt vector and 8259 mask state */
if (ap->vec != -1) {
(void) freevect (ap->vec);
(void) maskoff (ap->vec);
}
/* Restore speed regs */
setbit (base + LCR, LCR_DLAB);
outportb (base + DLL, ap->save.divl); /* Low byte */
outportb (base + DLM, ap->save.divh); /* Hi byte */
clrbit (base + LCR, LCR_DLAB);
/* Restore control regs */
outportb (base + LCR, ap->save.lcr);
outportb (base + IER, ap->save.ier);
outportb (base + MCR, ap->save.mcr);
if (ap->save.mask)
(void) maskon (ap->vec);
else
(void) maskoff (ap->vec);
free (ap->fifo.buf);
return 0;
}
/* Set asynch line speed */
int
asy_speed (int dev, int32 bps)
{
unsigned base;
long divisor;
struct asy *asyp;
int i_state;
if (dev >= ASY_MAX)
return -1;
asyp = &Asy[dev];
if (asyp->iface == NULL)
return -1;
if (bps == 0)
return -1;
asyp->speed = bps;
base = asyp->addr;
divisor = BAUDCLK / bps;
i_state = disable ();
/* Purge the receive data buffer */
(void) inportb (base + RBR);
if (asyp->is_16550a) /* clear tx+rx fifos */
outportb (base + FCR, FIFO_SETUP);
/* Turn on divisor latch access bit */
setbit (base + LCR, LCR_DLAB);
/* Load the two bytes of the register */
outportb (base + DLL, divisor); /* Low byte */
outportb (base + DLM, divisor >> 8); /*lint !e704 * Hi byte */
/* Turn off divisor latch access bit */
clrbit (base + LCR, LCR_DLAB);
restore (i_state);
return 0;
}
/* Asynchronous line I/O control */
int32
asy_ioctl (struct iface * ifp, int cmd, int set, int32 val)
{
struct asy *ap = &Asy[ifp->dev];
uint base = ap->addr;
switch (cmd) {
case PARAM_SPEED:
if (set)
(void) asy_speed (ifp->dev, val);
return ap->speed;
case PARAM_DTR:
if (set) {
writebit (base + MCR, MCR_DTR, (int) val);
ap->dtr_usage = (val) ? MOVED_UP : MOVED_DOWN;
}
return (inportb (base + MCR) & MCR_DTR) ? TRUE : FALSE;
case PARAM_RTS:
if (set) {
writebit (base + MCR, MCR_RTS, (int) val);
ap->rts_usage = (val) ? MOVED_UP : MOVED_DOWN;
}
return (inportb (base + MCR) & MCR_RTS) ? TRUE : FALSE;
case PARAM_DOWN:
clrbit (base + IER, (char) IER_DAV);
clrbit (base + MCR, MCR_RTS);
clrbit (base + MCR, MCR_DTR);
ap->rts_usage = MOVED_DOWN;
ap->dtr_usage = MOVED_DOWN;
return FALSE;
case PARAM_UP:
setbit (base + IER, (char) IER_DAV);
setbit (base + MCR, MCR_RTS);
setbit (base + MCR, MCR_DTR);
ap->rts_usage = MOVED_UP;
ap->dtr_usage = MOVED_UP;
return TRUE;
case PARAM_BLIND:
setbit (base + IER, (char) IER_DAV);
ap->rlsd_line_control = IGNORED;
if (ap->monitor != NULL) {
killproc (ap->monitor);
ap->monitor = NULL;
}
/* can't see what we are doing, so pretend we're up */
if (ifp->iostatus != NULL) {
(void) (*ifp->iostatus) (ifp, PARAM_UP, 0L);
}
return TRUE;
default:
return -1;
}
}
#if 0
/* Open an asynch port for direct I/O, temporarily suspending any
* packet-mode operations. Returns device number for asy_write and get_asy
*/
int
asy_open (char *name)
{
struct iface *ifp;
int dev;
if ((ifp = if_lookup (name)) == NULL) {
errno = ENODEV;
return -1;
}
if ((dev = ifp->dev) >= ASY_MAX || Asy[dev].iface != ifp) {
errno = EINVAL;
return -1;
}
/* Suspend the packet drivers */
suspend (ifp->rxproc);
suspend (ifp->txproc);
/* bring the line up (just in case) */
if (ifp->ioctl != NULL)
(void) (*ifp->ioctl) (ifp, PARAM_UP, TRUE, 0L);
return dev;
}
int
asy_close (int dev)
{
struct iface *ifp;
if (dev < 0 || dev >= ASY_MAX) {
errno = EINVAL;
return -1;
}
/* Resume the packet drivers */
if ((ifp = Asy[dev].iface) == NULL) {
errno = EINVAL;
return -1;
}
resume (ifp->rxproc);
resume (ifp->txproc);
return 0;
}
#endif
/* Send a buffer on the serial transmitter and wait for completion */
static int
asy_write (int dev, const void *buf, unsigned short cnt)
{
struct dma *dp;
unsigned base;
struct asy *asyp;
char ier;
int tmp;
int i_state;
struct iface *ifp;
if (dev < 0 || dev >= ASY_MAX)
return -1;
asyp = &Asy[dev];
if ((ifp = asyp->iface) == NULL)
return -1;
base = asyp->addr;
dp = &asyp->dma;
if (dp->flags)
return -1; /* Already busy */
dp->data = (uint8 *) buf;
dp->cnt = cnt;
dp->flags = 1;
/* If CTS flow control is disabled or CTS is true,
* enable transmit interrupts here so we'll take an immediate
* interrupt to get things going. Otherwise let the
* modem control interrupt enable transmit interrupts
* when CTS comes up. If we do turn on TxE,
* "kick start" the transmitter interrupt routine, in case just
* setting the interrupt enable bit doesn't cause an interrupt
*/
if (asyp->cts_flow_control & MOVED_DOWN) {
/* CTS flow control is enabled; let the modem control
* interrupt enable transmit interrupts if CTS is off
*/
ier = IER_MS;
if (inportb (base + MSR) & MSR_CTS)
ier |= IER_TxE;
} else {
/* Enable transmit interrupts; this will cause an immediate
* interrupt that will start things going
*/
ier = IER_TxE;
}
setbit (base + IER, ier);
/* Wait for completion */
for ( ; ; ) {
i_state = disable ();
tmp = dp->flags;
restore (i_state);
if (tmp == 0)
break;
kwait (&asyp->dma);
}
ifp->lastsent = secclock ();
return cnt;
}
/* Blocking read from asynch line
* Returns character or -1 if aborting
*/
int
get_asy (int dev)
{
struct fifo *fp;
uint8 c;
if (dev < 0 || dev >= ASY_MAX) {
errno = EINVAL;
return -1;
}
fp = &Asy[dev].fifo;
while (fp->cnt == 0) {
if (kwait (fp) != 0)
return -1;
}
(void) arddec ((volatile int *)&fp->cnt);
c = *fp->rp++;
if (fp->rp >= &fp->buf[fp->bufsize])
fp->rp = fp->buf;
return c;
}
/* Interrupt handler for 8250 asynch chip (called from asyvec.asm) */
static void
asyint (int dev)
{
#ifdef DEBUGASY
ierints++;
#endif
asycom (&Asy[dev]);
}
/* Common interrupt handler code for 8250/16550 port */
static void
asycom (struct asy *asyp)
{
unsigned base;
unsigned char iir;
base = asyp->addr;
while (((iir = inportb (base + IIR)) & IIR_IP) == 0) {
switch (iir & IIR_ID_MASK) {
case IIR_RLS:
if (inportb (base + LSR) & LSR_OE)
asyp->overrun++;
break;
case IIR_RDA: /* Receiver interrupt */
asyrxint (asyp, base);
break;
case IIR_THRE: /* Transmit interrupt */
asytxint (asyp, base);
break;
case IIR_MSTAT: /* Modem status change */
asymsint (asyp);
asyp->msint_count++;
break;
default:
break;
}
/* should happen at end of a single packet */
if (iir & IIR_FIFO_TIMEOUT)
asyp->fifotimeouts++;
}
}
/* Process 8250 receiver interrupts */
static void
asyrxint (struct asy *asyp, unsigned base)
{
struct fifo *fp;
uint8 c, lsr;
int cnt = 0;
int trigseen = FALSE;
asyp->rxints++;
fp = &asyp->fifo;
for ( ; ; ) {
lsr = inportb (base + LSR);
if (lsr & LSR_OE)
asyp->overrun++;
if (lsr & LSR_DR) {
asyp->rxchar++;
c = inportb (base + RBR);
if (asyp->trigchar == -1 || asyp->trigchar == c)
trigseen = TRUE;
/* If buffer is full, we have no choice but
* to drop the character
*/
if (fp->cnt != fp->bufsize) {
*fp->wp++ = c;
if (fp->wp >= &fp->buf[fp->bufsize])
/* Wrap around */
fp->wp = fp->buf;
fp->cnt++;
if (fp->cnt > fp->hiwat)
fp->hiwat = fp->cnt;
cnt++;
} else
fp->overrun++;
} else
break;
}
if (cnt > asyp->rxhiwat)
asyp->rxhiwat = cnt;
if (trigseen)
ksignal (fp, 1);
}
/* Handle 8250 transmitter interrupts */
static void
asytxint (struct asy *asyp, unsigned base)
{
struct dma *dp;
int count;
uint8 lsr;
dp = &asyp->dma;
asyp->txints++;
if (!dp->flags || !(asyp->msr & MSR_CTS)) {
/* These events "shouldn't happen". Either the
* transmitter is idle, in which case the transmit
* interrupts should have been disabled, or flow control
* is enabled but CTS is low, and interrupts should also
* have been disabled.
*/
clrbit (base + IER, IER_TxE);
return; /* Nothing to send */
}
lsr = inportb (base + LSR);
if (lsr & LSR_OE)
asyp->overrun++;
if ((lsr & LSR_THRE) == 0)
return; /* Not really ready */
/* If it's a 16550A, load up to 16 chars into the tx hw fifo
* at once. With an 8250, it can be one char at most.
*/
if (asyp->is_16550a) {
count = (int) min (dp->cnt, OUTPUT_FIFO_SIZE);
/* 16550A: LSR_THRE will drop after the first char loaded
* so we can't look at this bit to determine if the hw fifo is
* full. There seems to be no way to determine if the tx fifo
* is full (any clues?). So we should never get here while the
* fifo isn't empty yet.
*/
asyp->txchar += count;
dp->cnt -= count;
while (count-- != 0)
outportb (base + THR, *dp->data++);
} else { /* 8250 */
do {
asyp->txchar++;
outportb (base + THR, *dp->data++);
} while (--dp->cnt != 0 && (inportb (base + LSR) & LSR_THRE));
}
if (dp->cnt == 0) {
dp->flags = 0;
/* Disable further transmit interrupts */
clrbit (base + IER, IER_TxE);
ksignal (&asyp->dma, 1);
}
return;
}
/* Handle 8250 modem status change interrupt */
static void
asymsint (struct asy *ap)
{
unsigned base = ap->addr;
ap->msr = inportb(base+MSR);
if ( ap->msr & MSR_CTS ) {
switch ( ap->cts_flow_control ) {
case FOUND_DOWN:
case MOVED_DOWN:
ap->cts_flow_control = MOVED_UP;
/* CTS now asserted, enable Transmit interrupts */
if(ap->dma.flags)
setbit(base+IER,IER_TxE);
break;
default:
break;
};
} else {
switch ( ap->cts_flow_control ) {
case FOUND_UP:
case MOVED_UP:
ap->cts_flow_control = MOVED_DOWN;
/* CTS now dropped, disable Transmit interrupts */
clrbit(base+IER,IER_TxE);
break;
default:
break;
};
}
if ( ap->msr & MSR_RLSD ) {
switch ( ap->rlsd_line_control ) {
case FOUND_DOWN:
case MOVED_DOWN:
ap->rlsd_line_control = MOVED_UP;
/* RLSD just went up */
ksignal( &(ap->rlsd_line_control), 1 );
break;
default:
break;
};
} else {
switch ( ap->rlsd_line_control ) {
case FOUND_UP:
case MOVED_UP:
ap->rlsd_line_control = MOVED_DOWN;
/* RLSD just went down */
ksignal( &(ap->rlsd_line_control), 1 );
break;
default:
break;
};
}
if ( ap->msr & (MSR_TERI | MSR_RI) )
(void) asy_ioctl( ap->iface, PARAM_UP, TRUE, 0L );
}
END_OF_FUNCTION(asyint)
/* Wait for a signal that the RLSD modem status has changed */
static int
get_rlsd_asy (dev, new_rlsd)
int dev;
int new_rlsd;
{
struct asy *ap = &Asy[dev];
struct iface *ifp = ap->iface;
int result;
if ( ap->rlsd_line_control & IGNORED )
return IGNORED;
switch ( new_rlsd ) {
case IGNORED:
/* Just return the current value */
return(ap->rlsd_line_control);
case MOVED_DOWN:
if ( !(ap->rlsd_line_control & FOUND_UP) ) {
/* Already at requested value */
return(new_rlsd);
}
break;
case MOVED_UP:
if ( ap->rlsd_line_control & FOUND_UP ) {
/* Already at requested value */
return(new_rlsd);
}
break;
default:
break;
}
/* Wait for state change to requested value */
while (ap->rlsd_line_control != new_rlsd) {
kpause(2L);
kwait( &(ap->rlsd_line_control) );
}
if ( ap->rlsd_line_control & FOUND_UP )
result = PARAM_UP;
else /* DOWN or IGNORED */
result = PARAM_DOWN;
/* set our control signals to follow RLSD */
if ( ifp->ioctl != NULL )
(void) (*ifp->ioctl)( ifp, result, TRUE, 0L );
if ( ifp->iostatus != NULL )
(void) (*ifp->iostatus)( ifp, result, 0L );
return(ap->rlsd_line_control);
}
/* Monitor RLSD signal, and report status changes */
static void
asy_monitor (dev, p1, p2)
int dev;
void *p1;
void *p2;
{
int save_rlsd = Asy[dev].rlsd_line_control;
while (save_rlsd != IGNORED) {
save_rlsd = get_rlsd_asy (dev, (save_rlsd ^ FOUND_UP) | MOVED_DOWN);
kpause (2);
}
Asy[dev].monitor = NULL;
}
/* Poll the asynch input queues; called on every clock tick.
* This helps limit the interrupt ring buffer occupancy when long
* packets are being received.
*/
void
asytimer (void)
{
struct asy *asyp;
struct fifo *fp;
int i, i_state;
for (i = 0; i < ASY_MAX; i++) {
asyp = &Asy[i];
if (asyp->iface == NULLIF)
continue;
fp = &asyp->fifo;
if (fp->cnt != 0)
ksignal (fp, 1);
if (asyp->dma.flags && (inportb (asyp->addr + LSR) & LSR_THRE) &&
(inportb(asyp->addr+IER) & IER_TxE)) {
asyp->txto++;
i_state = disable ();
asytxint (asyp, asyp->addr);
restore (i_state);
}
#if 0 /* was def TIPMAIL */
if (Tipsuspended[i].ifp) {
if (!carrier_detect(i)) {
char buf[40];
sprintf (buf, "start tip %s %s %d\n", Tipsuspended[i].ifp->name, (Tipsuspended[i].modem) ? "m" : "t", Tipsuspended[i].timeout);
cmdparse(Cmds,buf,NULL);
Tipsuspended[i].ifp = 0;
Tipsuspended[i].modem = 0;
Tipsuspended[i].timeout = 0;
}
}
#endif
}
}
void
pasy (struct asy *asyp)
{
#ifdef DEBUGASY
int mcr, ier, iir;
#endif
tprintf ("%s:", asyp->iface->name);
if (asyp->is_16550a)
tprintf (" [NS16550A]");
if (asyp->trigchar != -1)
tprintf (" [trigger 0x%02x]", asyp->trigchar);
switch (asyp->cts_flow_control) {
case MOVED_DOWN:
case MOVED_UP:
tputs (" [cts flow control]");
break;
default:
break;
};
switch (asyp->rlsd_line_control) {
case MOVED_DOWN:
case MOVED_UP:
tputs (" [rlsd line control]");
break;
case IGNORED:
tputs (" [blind]");
break;
default:
break;
};
tprintf (" %lu bps - bufsize %d\n", asyp->speed, asyp->fifo.bufsize);
#ifdef DEBUGASY
ier = inportb (asyp->addr + IER);
tprintf (" IE: int %lu DAV %s TxE %s RLS %s MS %s\n",
ierints,
(ier & IER_DAV) ? "On" : "Off",
(ier & IER_TxE) ? "On" : "Off",
(ier & IER_RLS) ? "On" : "Off",
(ier & IER_MS) ? "On" : "Off");
iir = inportb (asyp->addr + IIR);
tprintf (" IR: int %s MS %s THRE %s RDA %s RLS %s\n",
!(iir & IIR_IP) ? "On" : "Off",
(((iir & IIR_ID_MASK) == IIR_MSTAT) && !(iir & IIR_IP)) ? "On" : "Off",
((iir & IIR_ID_MASK) == IIR_THRE) ? "On" : "Off",
((iir & IIR_ID_MASK) == IIR_RDA) ? "On" : "Off",
((iir & IIR_ID_MASK) == IIR_RLS) ? "On" : "Off");
mcr = inportb (asyp->addr + MCR);
tprintf (" MC: int %lu DTR %s RTS %s CTS %s DSR %s RI %s CD %s\n",
asyp->msint_count,
(mcr & MCR_DTR) ? "On" : "Off",
(mcr & MCR_RTS) ? "On" : "Off",
(asyp->msr & MSR_CTS) ? "On" : "Off",
(asyp->msr & MSR_DSR) ? "On" : "Off",
(asyp->msr & MSR_RI) ? "On" : "Off",
(asyp->msr & MSR_RLSD) ? "On" : "Off");
#endif
tprintf (" RX: int %lu chars %lu hw over %lu hw hi %lu\n ",
asyp->rxints, asyp->rxchar, asyp->overrun, asyp->rxhiwat);
asyp->rxhiwat = 0;
if (asyp->is_16550a)
tprintf ("fifo TO %lu ", asyp->fifotimeouts);
tprintf ("sw over %lu sw hi %u\n",
asyp->fifo.overrun, asyp->fifo.hiwat);
asyp->fifo.hiwat = 0;
tprintf (" TX: int %lu chars %lu THRE TO %lu%s\n",
asyp->txints, asyp->txchar, asyp->txto,
asyp->dma.flags ? " BUSY" : "");
}
/* Send a message on the specified serial line */
int
asy_send (dev, bpp)
int dev;
struct mbuf *bpp;
{
if (dev < 0 || dev >= ASY_MAX)
return -1;
while (bpp != NULL) {
/* Send the buffer */
(void) asy_write (dev, bpp->data, bpp->cnt);
/* Now do next buffer on chain */
bpp = free_mbuf (bpp);
}
return 0;
}
#endif